﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Diagnostics;
using System.Diagnostics.Contracts;
using System.Globalization;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media;
using OpenLS.UI.Internals;

namespace OpenLS.Spreadsheet.UI
{

#if DEBUG
    [ContractClass(typeof(DimensionsControlContract))]
#endif
    internal abstract class DimensionsControl : Control
    {



        public int Position
        {
            get { return (int)GetValue(PositionProperty); }
            set { SetValue(PositionProperty, value); }
        }

        // Using a DependencyProperty as the backing store for Position.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty PositionProperty =
            DependencyProperty.Register("Position", typeof(int), typeof(DimensionsControl), new FrameworkPropertyMetadata(0, FrameworkPropertyMetadataOptions.AffectsMeasure | FrameworkPropertyMetadataOptions.AffectsRender));

        
        public Brush ItemHoverSelectedBorderBrush
        {
            get { return (Brush)GetValue(ItemHoverSelectedBorderBrushProperty); }
            set { SetValue(ItemHoverSelectedBorderBrushProperty, value); }
        }

        // Using a DependencyProperty as the backing store for ItemHoverSelectedBorderBrush.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty ItemHoverSelectedBorderBrushProperty =
            DependencyProperty.Register("ItemHoverSelectedBorderBrush", typeof(Brush), typeof(DimensionsControl),
                                        new FrameworkPropertyMetadata(null,
                                                                      FrameworkPropertyMetadataOptions.AffectsRender,
                                                                      OnItemHoverSelectedBorderBrushChanged));

        private static void OnItemHoverSelectedBorderBrushChanged(DependencyObject d,
                                                                  DependencyPropertyChangedEventArgs e)
        {
            var c = (DimensionsControl)d;
            c.ItemHoverSelectedBorderPen = CreateFrozenPen(e.NewValue);
        }


        public Brush ItemHoverSelectedForeground
        {
            get { return (Brush)GetValue(ItemHoverSelectedForegroundProperty); }
            set { SetValue(ItemHoverSelectedForegroundProperty, value); }
        }

        // Using a DependencyProperty as the backing store for ItemHoverSelectedForeground.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty ItemHoverSelectedForegroundProperty =
            DependencyProperty.Register("ItemHoverSelectedForeground", typeof(Brush), typeof(DimensionsControl),
                                        new FrameworkPropertyMetadata(null,
                                                                      FrameworkPropertyMetadataOptions.AffectsRender));


        public Brush ItemHoverSelectedBackground
        {
            get { return (Brush)GetValue(ItemHoverSelectedBackgroundProperty); }
            set { SetValue(ItemHoverSelectedBackgroundProperty, value); }
        }

        // Using a DependencyProperty as the backing store for ItemHoverSelectedBackground.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty ItemHoverSelectedBackgroundProperty =
            DependencyProperty.Register("ItemHoverSelectedBackground", typeof(Brush), typeof(DimensionsControl),
                                        new FrameworkPropertyMetadata(null,
                                                                      FrameworkPropertyMetadataOptions.AffectsRender));


        public Brush ItemFullSelectedBorderBrush
        {
            get { return (Brush)GetValue(ItemFullSelectedBorderBrushProperty); }
            set { SetValue(ItemFullSelectedBorderBrushProperty, value); }
        }

        // Using a DependencyProperty as the backing store for ItemFullSelectedBorderBrush.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty ItemFullSelectedBorderBrushProperty =
            DependencyProperty.Register("ItemFullSelectedBorderBrush", typeof(Brush), typeof(DimensionsControl),
                                        new FrameworkPropertyMetadata(null,
                                                                      FrameworkPropertyMetadataOptions.AffectsRender,
                                                                      OnItemFullSelectedBorderBrushChanged));

        private static void OnItemFullSelectedBorderBrushChanged(DependencyObject d,
                                                                 DependencyPropertyChangedEventArgs e)
        {
            var c = (DimensionsControl)d;
            c.ItemFullSelectedBorderPen = CreateFrozenPen(e.NewValue);
        }


        public Brush ItemFullSelectedForeground
        {
            get { return (Brush)GetValue(ItemFullSelectedForegroundProperty); }
            set { SetValue(ItemFullSelectedForegroundProperty, value); }
        }

        // Using a DependencyProperty as the backing store for ItemFullSelectedForeground.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty ItemFullSelectedForegroundProperty =
            DependencyProperty.Register("ItemFullSelectedForeground", typeof(Brush), typeof(DimensionsControl),
                                        new FrameworkPropertyMetadata(null,
                                                                      FrameworkPropertyMetadataOptions.AffectsRender));


        public Brush ItemFullSelectedBackground
        {
            get { return (Brush)GetValue(ItemFullSelectedBackgroundProperty); }
            set { SetValue(ItemFullSelectedBackgroundProperty, value); }
        }

        // Using a DependencyProperty as the backing store for ItemFullSelectedBackground.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty ItemFullSelectedBackgroundProperty =
            DependencyProperty.Register("ItemFullSelectedBackground", typeof(Brush), typeof(DimensionsControl),
                                        new FrameworkPropertyMetadata(null,
                                                                      FrameworkPropertyMetadataOptions.AffectsRender));


        public IWorksheetFragment Fragment
        {
            get { return (IWorksheetFragment)GetValue(FragmentProperty); }
            set { SetValue(FragmentProperty, value); }
        }

        // Using a DependencyProperty as the backing store for Fragment.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty FragmentProperty =
            DependencyProperty.Register("Fragment", typeof(IWorksheetFragment), typeof(DimensionsControl),
                                        new FrameworkPropertyMetadata(null,
                                                                      FrameworkPropertyMetadataOptions.
                                                                          AffectsParentMeasure, new PropertyChangedCallback(OnFragmentChanged)));

        private static void OnFragmentChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            DimensionsControl c = (DimensionsControl)d;
            c.OnFragmentChanged(e);
        }
        void OnFragmentChanged(DependencyPropertyChangedEventArgs e)
        {
            WorksheetPane oldPane = (WorksheetPane)e.OldValue;
            WorksheetPane newPane = (WorksheetPane)e.NewValue;
            if (oldPane != null)
                oldPane.LayoutChanged -= OnLayoutChanged;
            if (newPane != null)
                newPane.LayoutChanged += OnLayoutChanged;
        }

        private void OnLayoutChanged(object sender, EventArgs e)
        {

            this.InvalidateMeasure();
            InvalidateVisual();
        }

        public static readonly DependencyProperty ItemsSourceProperty =
            DependencyProperty.Register("ItemsSource", typeof(IEnumerable), typeof(DimensionsControl),
                                        new FrameworkPropertyMetadata(null,
                                                                      FrameworkPropertyMetadataOptions.AffectsRender,
                                                                      OnItemsSourceChanged));

        public static readonly DependencyProperty SelectionProperty =
            DependencyProperty.Register("Selection", typeof(Range), typeof(DimensionsControl),
                                        new FrameworkPropertyMetadata(null,
                                                                      FrameworkPropertyMetadataOptions.AffectsRender));

        public static readonly DependencyProperty ItemHoverBackgroundProperty =
            DependencyProperty.Register("ItemHoverBackground", typeof(Brush), typeof(DimensionsControl),
                                        new FrameworkPropertyMetadata(null,
                                                                      FrameworkPropertyMetadataOptions.AffectsRender));

        public static readonly DependencyProperty ItemHoverBorderBrushProperty =
            DependencyProperty.Register("ItemHoverBorderBrush", typeof(Brush), typeof(DimensionsControl),
                                        new FrameworkPropertyMetadata(null,
                                                                      FrameworkPropertyMetadataOptions.AffectsRender,
                                                                      OnItemHoverBorderBrushChanged));

        private static void OnItemHoverBorderBrushChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            var c = (DimensionsControl)d;
            c.ItemHoverBorderPen = CreateFrozenPen(e.NewValue);
        }

        public static readonly DependencyProperty ItemSelectedBackgroundProperty =
            DependencyProperty.Register("ItemSelectedBackground", typeof(Brush), typeof(DimensionsControl),
                                        new FrameworkPropertyMetadata(null,
                                                                      FrameworkPropertyMetadataOptions.AffectsRender));

        public static readonly DependencyProperty ItemSelectedBorderBrushProperty =
            DependencyProperty.Register("ItemSelectedBorderBrush", typeof(Brush), typeof(DimensionsControl),
                                        new FrameworkPropertyMetadata(null,
                                                                      FrameworkPropertyMetadataOptions.AffectsRender,
                                                                      OnItemSelectedBorderBrushChanged));

        private static void OnItemSelectedBorderBrushChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            var c = (DimensionsControl)d;
            c.ItemSelectedBorderPen = CreateFrozenPen(e.NewValue);
        }

        static DimensionsControl()
        {
            DefaultStyleKeyProperty.OverrideMetadata(typeof(DimensionsControl),
                                                     new FrameworkPropertyMetadata(typeof(DimensionsControl)));
        }


        public IEnumerable ItemsSource
        {
            get { return (IEnumerable)GetValue(ItemsSourceProperty); }
            set { SetValue(ItemsSourceProperty, value); }
        }

        // Using a DependencyProperty as the backing store for ItemsSource.  This enables animation, styling, binding, etc...


        public Range Selection
        {
            get { return (Range)GetValue(SelectionProperty); }
            set { SetValue(SelectionProperty, value); }
        }


        public Brush ItemSelectedForeground
        {
            get { return (Brush)GetValue(ItemSelectedForegroundProperty); }
            set { SetValue(ItemSelectedForegroundProperty, value); }
        }

        // Using a DependencyProperty as the backing store for ItemSelectedForeground.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty ItemSelectedForegroundProperty =
            DependencyProperty.Register("ItemSelectedForeground", typeof(Brush), typeof(DimensionsControl),
                                        new FrameworkPropertyMetadata(null,
                                                                      FrameworkPropertyMetadataOptions.AffectsRender));


        public Brush ItemHoverForeground
        {
            get { return (Brush)GetValue(ItemHoverForegroundProperty); }
            set { SetValue(ItemHoverForegroundProperty, value); }
        }

        // Using a DependencyProperty as the backing store for ItemHoverForeground.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty ItemHoverForegroundProperty =
            DependencyProperty.Register("ItemHoverForeground", typeof(Brush), typeof(DimensionsControl),
                                        new FrameworkPropertyMetadata(null,
                                                                      FrameworkPropertyMetadataOptions.AffectsRender));


        // Using a DependencyProperty as the backing store for Selection.  This enables animation, styling, binding, etc...


        public Brush ItemHoverBackground
        {
            get { return (Brush)GetValue(ItemHoverBackgroundProperty); }
            set { SetValue(ItemHoverBackgroundProperty, value); }
        }

        // Using a DependencyProperty as the backing store for ItemHoverBackground.  This enables animation, styling, binding, etc...


        public Brush ItemHoverBorderBrush
        {
            get { return (Brush)GetValue(ItemHoverBorderBrushProperty); }
            set { SetValue(ItemHoverBorderBrushProperty, value); }
        }

        // Using a DependencyProperty as the backing store for ItemHoverBorderBrush.  This enables animation, styling, binding, etc...


        public Brush ItemSelectedBackground
        {
            get { return (Brush)GetValue(ItemSelectedBackgroundProperty); }
            set { SetValue(ItemSelectedBackgroundProperty, value); }
        }

        // Using a DependencyProperty as the backing store for ItemSelectedBackground.  This enables animation, styling, binding, etc...


        public Brush ItemSelectedBorderBrush
        {
            get { return (Brush)GetValue(ItemSelectedBorderBrushProperty); }
            set { SetValue(ItemSelectedBorderBrushProperty, value); }
        }


        public Brush ItemBorderBrush
        {
            get { return (Brush)GetValue(ItemBorderBrushProperty); }
            set { SetValue(ItemBorderBrushProperty, value); }
        }

        // Using a DependencyProperty as the backing store for ItemBorderBrush.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty ItemBorderBrushProperty =
            DependencyProperty.Register("ItemBorderBrush", typeof(Brush), typeof(DimensionsControl),
                                        new FrameworkPropertyMetadata(null,
                                                                      FrameworkPropertyMetadataOptions.AffectsRender,
                                                                      OnItemBorderBrushChanged));

        private static void OnItemBorderBrushChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            var c = (DimensionsControl)d;
            c.ItemBorderPen = CreateFrozenPen(e.NewValue);
        }

        private static Pen CreateFrozenPen(object obj)
        {
            var brush = (Brush)obj;
            if (brush == null)
                return null;
            var result = new Pen(brush, 1);
            result.Freeze();
            return result;
        }

        private Pen ItemBorderPen;


        private static void OnItemsSourceChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            var c = (DimensionsControl)d;
            c.OnItemsSourceChanged(e);
        }

        private void OnItemsSourceChanged(DependencyPropertyChangedEventArgs e)
        {
            var oldValue = e.OldValue as INotifyCollectionChanged;
            var newValue = e.NewValue as INotifyCollectionChanged;
            if (oldValue != null)
                oldValue.CollectionChanged -= OnItemsSourceCollectionChanged;
            if (newValue != null)
                newValue.CollectionChanged += OnItemsSourceCollectionChanged;
        }

        private void OnItemsSourceCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
        {
            InvalidateMeasure();
        }

        protected abstract override Size MeasureOverride(Size constraint);

        protected override void OnRender(DrawingContext drawingContext)
        {
            base.OnRender(drawingContext);
            if (Background != null)
                drawingContext.DrawRectangle(Background, null, new Rect(0, 0, ActualWidth, ActualHeight));
            if (ItemsSource == null || Fragment == null)
                return;
            RenderItems(drawingContext);
        }

        protected Typeface GetTypeFace()
        {
            return SpreadsheetFont.CreateTypeface(FontFamily, FontStyle, FontWeight);
        }

        protected void RenderItems(DrawingContext drawingContext)
        {
            Typeface typeface = GetTypeFace();
            this.layoutRounder = new LayoutRounder(this);
            double size = FontSize;

            bool canRenderItems = (ItemsSource != null);
            if (!canRenderItems) return;

            canRenderItems = ((Fragment != null));
            if (!canRenderItems) return;


            canRenderItems = ((ItemBorderPen == null) == (ItemBorderBrush == null));
            if (!canRenderItems) return;

            /*
            Contract.Assert(ItemsSource != null);
            Contract.Assert((Fragment != null));
            Contract.Assert((ItemBorderPen == null) == (ItemBorderBrush == null));
            */

            foreach (Dimension d in Enumerable.Where(Dimensions, i => i.IsVisible && !i.IsSelected && i != HoverItem))
            {
                DrawItem(d, drawingContext, typeface, Foreground, null, ItemBorderPen, false);

            }
            if (Selection != null)
            {
                Brush background;
                Brush foreground;
                Pen border;
                if (Selection.IsFullColumn || Selection.IsFullRow)
                {
                    background = ItemFullSelectedBackground;
                    foreground = ItemFullSelectedForeground;
                    border = ItemFullSelectedPen;
                }
                else
                {
                    background = ItemSelectedBackground;
                    foreground = ItemSelectedForeground;
                    border = ItemSelectedPen;
                }
                foreground = foreground ?? Foreground;
                border = border ?? ItemBorderPen;
                foreach (Dimension d in Enumerable.Where(Dimensions, i => i.IsVisible && i.IsSelected && i != HoverItem))
                {
                    DrawItem(d, drawingContext, typeface, foreground, background, border, true);
                }
            }
            if (HoverItem != null)
            {
                Brush background;
                Brush foreground;
                Pen border;
                if (Selection != null &&
                    ((HoverItem is Column && Selection.ContainsColumn((Column)HoverItem)) ||
                     (HoverItem is Row && Selection.ContainsRow((Row)HoverItem))))
                {
                    background = ItemHoverSelectedBackground;
                    foreground = ItemHoverSelectedForeground;
                    border = ItemHoverSelectedBorderPen;
                }
                else
                {
                    background = ItemHoverBackground;
                    foreground = ItemHoverForeground;
                    border = ItemHoverBorderPen;
                }
                foreground = foreground ?? Foreground;
                DrawItem(HoverItem, drawingContext, typeface, foreground, background, border, true);
            }
        }

        private LayoutRounder layoutRounder;
        private void DrawItem(Dimension dimension, DrawingContext drawingContext, Typeface typeface, Brush foreground,
                              Brush background, Pen border, bool includePrevious)
        {
            Contract.Requires(layoutRounder != null);
            Contract.Requires(border == null || border.Thickness == 1);
            Rect rect = GetRect(dimension);
            rect = new Rect(layoutRounder.RoundLinePoint(rect.TopLeft, 1), layoutRounder.RoundLinePoint(rect.BottomRight, 1));
            drawingContext.DrawRectangle(background, null, rect);
            if (this is RowsControl)
            {
                if (includePrevious)
                    drawingContext.DrawLine(border, new Point(rect.Left, rect.Top), new Point(rect.Right, rect.Top));
                
            }
            else
                drawingContext.DrawLine(border, new Point(rect.Left, rect.Top), new Point(rect.Right, rect.Top));
            drawingContext.DrawLine(border, new Point(rect.Right, rect.Top), new Point(rect.Right, rect.Bottom));
            drawingContext.DrawLine(border, new Point(rect.Right, rect.Bottom), new Point(rect.Left, rect.Bottom));
            if (this is ColumnsControl)
            {
                if (includePrevious)
                    drawingContext.DrawLine(border, new Point(rect.Left, rect.Bottom), new Point(rect.Left, rect.Top));
            }
            else
                drawingContext.DrawLine(border, new Point(rect.Left, rect.Bottom), new Point(rect.Left, rect.Top));

            foreground = foreground ?? Foreground;
            if (foreground != null)
            {
                var formattedText = new FormattedText(dimension.Label, CultureInfo.CurrentUICulture,
                                                      FlowDirection.LeftToRight,
                                                      typeface, FontSize, foreground);
                drawingContext.PushClip(new RectangleGeometry(rect));
                drawingContext.DrawText(formattedText, new Point(rect.Left + (rect.Width - formattedText.Width) / 2,
                                                                 rect.Top + (rect.Height - formattedText.Height) / 2));
                drawingContext.Pop();
            }
        }

        protected IEnumerable<Dimension> Dimensions
        {
            get
            {
                foreach (Dimension d in ItemsSource)
                    yield return d;
            }
        }

        // Using a DependencyProperty as the backing store for ItemSelectedBorderBrush.  This enables animation, styling, binding, etc...


        public Dimension HoverItem
        {
            get { return (Dimension)GetValue(HoverItemProperty); }
            set { SetValue(HoverItemProperty, value); }
        }

        // Using a DependencyProperty as the backing store for HoverItem.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty HoverItemProperty =
            DependencyProperty.Register("HoverItem", typeof(Dimension), typeof(DimensionsControl),
                                        new FrameworkPropertyMetadata(null,
                                                                      FrameworkPropertyMetadataOptions.AffectsRender));

        private Pen ItemSelectedBorderPen;
        private Pen ItemHoverBorderPen;
        private Pen ItemFullSelectedBorderPen;
        private Pen ItemFullSelectedPen;
        private Pen ItemSelectedPen;
        private Pen ItemHoverSelectedBorderPen;
        private Dimension _capturedDimension;
        private Dimension _borderDimension;
        private Point dragPoint;

        protected override void OnMouseLeave(MouseEventArgs e)
        {
            HoverItem = null;
        }

        protected bool IsEmpty
        {
            get
            {
                if (ItemsSource == null)
                    return true;
                return !Enumerable.Any(Enumerable.Cast<Dimension>(ItemsSource), i => true);
            }
        }

        protected override void OnMouseMove(MouseEventArgs e)
        {
            if (IsEmpty)
            {
                HoverItem = null;
                return;
            }
            Point position = e.GetPosition(this);
            if (_borderDimension != null)
            {
                DragDimension(_borderDimension, position - dragPoint);
                dragPoint = position;
                InvalidateVisual();
                return;
            }
            DimensionHit hit = GetHit(position);
            if (hit == null)
                return;
            HoverItem = hit.Dimension;
            if (Mouse.Captured == null)
            {
                return;
            }
            if (_capturedDimension != null)
            {
                OnMouseDimension(_capturedDimension);
            }
            else
            {
                Debug.WriteLine("no current dimension");
                return;
            }
        }

        protected abstract void DragDimension(Dimension borderDimension, Vector vector);


        protected abstract void OnMouseDimension(Dimension dimension);

        protected Dimension GetItemAt(Point position)
        {
            Contract.Ensures(Contract.Result<Dimension>() != null);
            Contract.Assert(Enumerable.Count(Enumerable.Cast<Dimension>(ItemsSource)) > 0);
            position = new Point(Math.Max(Math.Min(position.X, ActualWidth), 0), Math.Max(Math.Min(position.Y, ActualHeight), 0));
            foreach (Dimension d in ItemsSource)
            {
                Rect r = GetRect(d);
                if (r.Contains(position))
                    return d;
            }
            // Contract.Assert(false);
            return null;
        }

#if DEBUG
        [ContractClassFor(typeof(DimensionsControl))]
        private abstract class DimensionsControlContract : DimensionsControl
        {
            protected override Rect GetRect(Dimension dimension)
            {
                Contract.Requires(dimension != null);
                throw new NotSupportedException();
            }
        }
#endif
        protected abstract Rect GetRect(Dimension dimension);

        protected override void OnMouseDown(MouseButtonEventArgs e)
        {
            if (IsEmpty)
                return;
            Point position = e.GetPosition(this);
            DimensionHit h = GetHit(position);
            if (h == null)
                return;
            if (h.Dimension != null)
                SelectDimension(h.Dimension, e.ChangedButton);
            else
            {
                // Contract.Assert(h.BorderDimesion != null);
                bool isDimensionSet = (h.BorderDimesion != null);
                if (!isDimensionSet) return;

                _borderDimension = h.BorderDimesion;
                dragPoint = position;
                Mouse.Capture(this);
            }
            Focus();
            base.OnMouseDown(e);
            e.Handled = true;
        }

        protected abstract DimensionHit GetHit(Point point);

        protected class DimensionHit
        {
            private readonly Dimension _borderDimension;
            private readonly Dimension _dimension;

            public DimensionHit(Dimension dimension, Dimension borderDimension)
            {
                Contract.Requires((dimension == null) != (borderDimension == null));
                _dimension = dimension;
                _borderDimension = borderDimension;
            }

            public Dimension Dimension
            {
                get { return _dimension; }
            }

            public Dimension BorderDimesion
            {
                get { return _borderDimension; }
            }
        }

        protected override void OnMouseUp(MouseButtonEventArgs e)
        {
            if (_borderDimension != null)
            {
                FinishDragDimension(_borderDimension);
            }

            Mouse.Capture(null);
            _capturedDimension = null;
            this._borderDimension = null;
            base.OnMouseUp(e);
        }

        protected abstract void FinishDragDimension(Dimension borderDimension);

        protected abstract void SelectDimension(Dimension d, MouseButton argsChangedButton);
        protected abstract override void OnQueryCursor(QueryCursorEventArgs e);
        protected const double tolerance = 3;

        internal static MergeType GetMergeType()
        {
            if (Keyboard.IsKeyDown(Key.LeftShift) || Keyboard.IsKeyDown(Key.RightShift))
                return MergeType.Extend;
            if (Keyboard.IsKeyDown(Key.LeftCtrl) || Keyboard.IsKeyDown(Key.RightCtrl))
                return MergeType.Union;
            return MergeType.None;
        }

        protected void CaptureDimension(Dimension dimension)
        {
            _capturedDimension = dimension;
            Mouse.Capture(this);
        }
    }
}